package netty.demo.nio.selector.write.improve;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;

/**
 * @author Zed
 * @description 改善缓冲区满了写不了内容的时候去进行读操作
 * @date 2022/10/24 20:19
 */
public class WriteServer {
    public static void main(String[] args) {
        try {
            ServerSocketChannel ssc = ServerSocketChannel.open();
            ssc.configureBlocking(false);
            Selector selector = Selector.open();
            ssc.register(selector, SelectionKey.OP_ACCEPT);
            ssc.bind(new InetSocketAddress(8080));
            while (true) {
                selector.select();
                Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();
                while (keyIterator.hasNext()) {
                    SelectionKey key = keyIterator.next();
                    keyIterator.remove();
                    if (key.isAcceptable()) {
                        SocketChannel channel = ssc.accept();
                        channel.configureBlocking(false);
                        SelectionKey selectionKey = channel.register(selector, 0, null);
                        selectionKey.interestOps(SelectionKey.OP_READ);
                        //1.向客户端发送大量数据
                        StringBuilder stringBuilder = new StringBuilder();
                        for (int i = 0; i < 5000000; i++) {
                            stringBuilder.append("a");
                        }
                        ByteBuffer byteBuffer = Charset.defaultCharset().encode(stringBuilder.toString());
                        //2.返回值,实际写入的字节数
                        int write = channel.write(byteBuffer);
                        System.out.println(write);
                        //3.判断是否有剩余内容
                        if (byteBuffer.hasRemaining()) {
                            //4.关注可写事件
                            selectionKey.interestOps(selectionKey.interestOps() + SelectionKey.OP_WRITE);
                            //5.未写完的数据挂载到 selectionKey上
                            selectionKey.attach(byteBuffer);
                        }
                    } else if (key.isWritable()) {
                        ByteBuffer byteBuffer = (ByteBuffer) key.attachment();
                        SocketChannel sc = (SocketChannel) key.channel();
                        int write = sc.write(byteBuffer);
                        System.out.println(write);
                        //6.清理操作
                        if (!byteBuffer.hasRemaining()) {
                            //如果都写完了，清除buffer
                            key.attach(null);
                            //不再需要关注可写事件
                            key.interestOps(key.interestOps() - SelectionKey.OP_WRITE);
                        }
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
